#include <stdio.h>
#include <stdbool.h>
#include <stdlib.h>
#include <string.h>

// 输入缓冲区
typedef struct
{
  char *buffer;
  size_t buffer_length;
  ssize_t input_length;
} InputBuffer;

// 元命令处理结果
typedef enum
{
  META_COMMAND_SUCCESS,
  META_COMMAND_UNRECOGNIZED_COMMAND
} MetaCommandResult;


// 预处理SQL结果
typedef enum
{
  PREPARE_SUCCESS,
  PREPARE_UNRECOGNIZED_STATEMENT
} PrepareResult;

// SQL语句类型
typedef enum
{
  STATEMENT_INSERT,
  STATEMENT_SELECT
} StatementType;

// SQL语句
typedef struct
{
  StatementType type;
} Statement;

void print_prompt();
void read_input(InputBuffer *input_buffer);
void close_input_buffer(InputBuffer *input_buffer);
MetaCommandResult do_meta_command(InputBuffer *input_buffer);
PrepareResult prepare_statement(InputBuffer *inputBuffer, Statement* statement);
void execute_statement(Statement* statement);

InputBuffer *new_input_buffer()
{
  InputBuffer *input_buffer = (InputBuffer *)malloc(sizeof(InputBuffer));
  input_buffer->buffer = NULL;
  input_buffer->buffer_length = 0;
  input_buffer->input_length = 0;

  return input_buffer;
}

int main(int argc, char *argv[])
{
  InputBuffer *input_buffer = new_input_buffer();
  while (true)
  {
    print_prompt();
    read_input(input_buffer);

    // 如果是点开头的命令（元命令），注意不要使用双引号。。。
    if (input_buffer->buffer[0] == '.')
    {
      switch (do_meta_command(input_buffer))
      {
      case META_COMMAND_SUCCESS:
        continue;
      case META_COMMAND_UNRECOGNIZED_COMMAND:
        printf("Unrecognized command '%s'\n", input_buffer->buffer);
        continue;
      default:
        break;
      }
    }

    // 如果是SQL语句
    Statement statement;
    switch (prepare_statement(input_buffer, &statement))
    {
    case PREPARE_SUCCESS:
      break;
    case PREPARE_UNRECOGNIZED_STATEMENT:
      printf("Unrecognized keyword at start of '%s'.\n", input_buffer->buffer);
      continue;
    default:
      break;
    }

    // 虚拟机执行语句
    execute_statement(&statement);
    printf("Executed.\n");

  }
}

void print_prompt()
{
  printf("db > ");
}

void read_input(InputBuffer *input_buffer)
{
  ssize_t bytes_read = getline(&(input_buffer->buffer), &(input_buffer->buffer_length), stdin);

  if (bytes_read <= 0)
  {
    printf("Error reading input\n");
    exit(EXIT_FAILURE);
  }

  // 忽略最后的换行符
  input_buffer->input_length = bytes_read - 1;
  input_buffer->buffer[bytes_read - 1] = 0;
}

void close_input_buffer(InputBuffer *input_buffer)
{
  free(input_buffer->buffer);
  free(input_buffer);
}

// 处理元命令
MetaCommandResult do_meta_command(InputBuffer *input_buffer)
{
  if (strcmp(input_buffer->buffer, ".exit") == 0)
  {
    exit(EXIT_SUCCESS);
  }
  else
  {
    return META_COMMAND_UNRECOGNIZED_COMMAND;
  }
}

PrepareResult prepare_statement(InputBuffer *inputBuffer, Statement* statement)
{
  // 如果是insert语句
  if (strncmp(inputBuffer->buffer, "insert", 6) == 0)
  {
    // 将statemnt中的type改成insert
    statement->type = STATEMENT_INSERT;
    return PREPARE_SUCCESS;
  }

  // 同理
  if (strcmp(inputBuffer->buffer, "select") == 0) 
  {
    statement->type = STATEMENT_SELECT;
    return PREPARE_SUCCESS;
  }

  return PREPARE_UNRECOGNIZED_STATEMENT;
}

// 虚拟机
void execute_statement(Statement* statement)
{
  switch (statement->type)
  {
  case STATEMENT_INSERT:
    printf("VM will do insert!\n");
    break;
  case STATEMENT_SELECT:
    printf("VM will do select!\n");
    break; 
  }
}